/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
import { Cookie } from "../Cookie"
import { CookieJar } from "../CookieJar"
import { Chain, Interceptor } from "../Interceptor"
import { Response } from "../Response"
import { List } from "@kit.ArkTS"
import { toHostHeader, userAgent } from "../utils/Utils"
import { promisesBody, receiveHeaders } from "./HttpHeaders"
import { RealResponseBody } from "./RealResponseBody"

/**
 * Bridges from application code to network code. First it builds a network request from a user
 * request. Then it proceeds to call the network. Finally it builds a user response from the network
 * response.
 */
export class BridgeInterceptor implements Interceptor {
  private cookieJar: CookieJar
  constructor(cookieJar: CookieJar) {
    this.cookieJar = cookieJar
  }

  // @Throws(IOException::class)
  async intercept(chain: Chain): Promise<Response> {
    let userRequest = chain.request()
    let requestBuilder = userRequest.newBuilder()
    let body = userRequest.body
    if (body !== null && body !== undefined) {
      let contentType = body.contentType()
      if (contentType !== null && contentType !== undefined) {
        requestBuilder.header("Content-Type", contentType.toString())
      }

      let contentLength = await body.contentLength()
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", contentLength.toString())
        requestBuilder.removeHeader("Transfer-Encoding")
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked")
        requestBuilder.removeHeader("Content-Length")
      }
    }

    if (userRequest.header("Host") === null || userRequest.header("Host") === undefined) {
      requestBuilder.header("Host", toHostHeader(userRequest.url))
    }

    if (userRequest.header("Connection") === null || userRequest.header("Connection") === undefined) {
      requestBuilder.header("Connection", "Keep-Alive")
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    let transparentGzip = false
    if ((userRequest.header("Accept-Encoding") === null || userRequest.header("Accept-Encoding") === undefined) && 
        (userRequest.header("Range") === null || userRequest.header("Range") === undefined)) {
      transparentGzip = true
      requestBuilder.header("Accept-Encoding", "gzip")
    }

    let cookies = this.cookieJar.loadForRequest(userRequest.url)
    if (cookies !== undefined && !cookies.isEmpty()) {
      requestBuilder.header("Cookie", this.cookieHeader(cookies))
    }

    if (userRequest.header("User-Agent") === null || userRequest.header("User-Agent") === undefined) {
      requestBuilder.header("User-Agent", userAgent)
    }
    console.log("okhttp test log :: " , "BridgeInterceptor : 上半段结束")
    let networkResponse = await chain.proceed(requestBuilder.build())

    receiveHeaders(this.cookieJar,userRequest.url, networkResponse.headers)

    let responseBuilder = networkResponse.newBuilder()
      .request(userRequest)

    if (transparentGzip && networkResponse.header("Content-Encoding")?.toLowerCase() === "gzip" && promisesBody(networkResponse)) {
      let responseBody = networkResponse.body
      if (responseBody !== null && responseBody !== undefined) {
        responseBody.source().isGzip = true
        let s = responseBody.source()
        let strippedHeaders = networkResponse.headers.newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build()
        responseBuilder.headers(strippedHeaders)
        let contentType = networkResponse.header("Content-Type")
        responseBuilder.body(new RealResponseBody(contentType, -1, responseBody.source()))
      }
    }
    console.log("okhttp test log :: " , "BridgeInterceptor : 下半段结束")

    return responseBuilder.build()
  }

  /** Returns a 'Cookie' HTTP request header with all cookies, like `a=b; c=d`. */
  private cookieHeader(cookies: List<Cookie>): string {
    let result = ""
    cookies.forEach((cookie,index) => {
      if (index > 0) result += "; "
      result += cookie.name + "=" + cookie.value
    })
    return result
  }
}
